package org.concepts.java.classloader.hello;

import org.concepts.java.classloader.utils.ClassLoaderUtils;

import com.vladium.utils.ClassLoaderResolver;
import com.vladium.utils.ResourceLoader;

/**
 * Prints various classloaders that are available to a class. It also prints out
 * the parent of all the classloader. The goal of this class to help you
 * understand the various locations from which classes can be loaded/accessed.
 * <p/>
 * After running this class, go through the <a target="_blank" href=
 * "http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html"
 * >thread context classloader </a> article. It'll help you understand various
 * classloader issues. The classes in the article are also part of this project.
 * Please go through {@link ClassLoaderResolver} and {@link ResourceLoader}
 * 
 * <h2>Reference</h2>
 * <ol>
 * <li><a target="_blank"
 * href="http://onjava.com/pub/a/onjava/2005/01/26/classloading.html"
 * >http://onjava.com/pub/a/onjava/2005/01/26/classloading.html</a>: Internals
 * of classloading</li>
 * <li>[JW] <a target="_blank" href=
 * "http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html"
 * >http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html</a> :
 * Why should Thread context classloader be used.</li>
 * </ol>
 * 
 * @author vvvv
 * 
 */
public class Hello {

  public static void main(String[] args) throws ClassNotFoundException {

    /*
     * [JW] "Current classloader loads and defines the class to which your
     * current method belongs. This classloader is implied when dynamic links
     * between classes resolve at runtime, and when you use the one-argument
     * version of Class.forName(), Class.getResource(), and similar methods. It
     * is also used by syntactic constructs like X.class class literals."
     */
    ClassLoader currentClassCL = Hello.class.getClassLoader();
    System.out.println("Current class ClassLoader [" + currentClassCL + "]");
    ClassLoaderUtils.printParentCLs(currentClassCL);

    /*
     * [JW] "Each thread has a context classloader. It was introduced in J2SE
     * when the default parent first delegation model did not prove sufficient
     * to load classes. E.g. If the factory method to load implementation is in
     * parent classloader but the implementation is in the child classloader.
     * <p/> This context classloaders provides a back door around the
     * classloading delegation scheme also introduced in J2SE. Normally, all
     * classloaders in a JVM are organized in a hierarchy such that every
     * classloader (except for the primordial classloader that bootstraps the
     * entire JVM) has a single parent. When asked to load a class, every
     * compliant classloader is expected to delegate loading to its parent first
     * and attempt to define the class only if the parent fails."
     */
    ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
    System.out.println("\nThread Context ClassLoader [" + contextCL + "]");
    ClassLoaderUtils.printParentCLs(contextCL);

    // System classloader. It handles that -classpath passed to Java
    // System classloader is also referred to as Application class loader
    ClassLoader systemCL = ClassLoader.getSystemClassLoader();
    System.out.println("\nSystem ClassLoader [" + systemCL + "] ");
    ClassLoaderUtils.printParentCLs(systemCL);

    /*
     * See ResourceLoader class that helps you intelligently choose the
     * classloader that should be used to load a class
     */
    Class hashMapClass = ResourceLoader.loadClass("java.util.HashMap");
    System.out
        .println("\nClassLoader ["
            + hashMapClass.getClassLoader()
            + "] "
            + " used to load class ["
            + hashMapClass
            + "]. NOTE: 'null' for "
            + "ClassLoader indicates that Bootstrap classsloader was used to load j"
            + "the class");

  }

}
